package com.zhny.aiot.adjust.valve.plugin;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import com.zhny.aiot.adjust.valve.plugin.model.AdjustValveStoreEntry;
import com.zhny.aiot.adjust.valve.plugin.model.AdjustableParam;
import com.zhny.aiot.plugin.ICenterFacilities;
import com.zhny.aiot.plugin.IDeviceFactory;
import com.zhny.aiot.plugin.core.utils.MessageUtils;
import com.zhny.aiot.plugin.model.DeviceEntity;
import com.zhny.aiot.plugin.model.MessageEntry;
import com.zhny.aiot.plugin.model.MessageType;
import com.zhny.aiot.plugin.model.TaskEntity;
import com.zhny.aiot.plugin.zhnygateway.GatewayEngine;
import com.zhny.aiot.plugin.zhnygateway.device.ZhnyConfig;
import com.zhny.aiot.plugin.zhnygateway.device.ZhnyDevice;
import com.zhny.aiot.plugin.zhnygateway.model.GatewayResponseMessage;
import com.zhny.aiot.plugin.zhnygateway.model.NodeRequestMessage;
import org.pf4j.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

public class AdjustableDevice extends ZhnyDevice<AdjustValveStoreEntry> {
    private static final Logger logger = LoggerFactory.getLogger(AdjustableDevice.class);
    private final Map<String, Integer> CommandOperations;
    public AdjustableDevice(GatewayEngine engine, IDeviceFactory<ZhnyConfig> factory, ICenterFacilities centerFacilities, DeviceEntity entity) {
        super (engine, factory, centerFacilities,entity);
        CommandOperations =  new ImmutableMap.Builder<String, Integer>()
                .put("openValve1", 0x01)
                .put("openValve2", 0x03)
                .put("openValve3", 0x05)
                .put("openValve4", 0x07)
                .put("queryStatus", 0x09)
                .put("queryVoltage", 0x0B).build();
    }
    protected NodeRequestMessage onCommand(TaskEntity taskEntity) {
        AdjustableParam param = null;
        if(StringUtils.isNullOrEmpty (taskEntity.getMethodName ()))
            return null;
        if(!StringUtils.isNullOrEmpty(taskEntity.getParams ())){
            ObjectMapper mapper = new ObjectMapper();
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            try{
                param = mapper.readValue (taskEntity.getParams (),AdjustableParam.class);
            }catch (Exception e){
                logger.error ("Parse param error !");
                return  null;
            }
        }
        Map<String,Object> command = new HashMap<String, Object> ();
        command.put (taskEntity.getMethodName (),param);
        logger.info ("config address[{}]",Integer.parseInt (getConfig ().getAddress ()));
        return encode (command);
    }

    @Override
    protected int getzhnyType() {
        return 22;
    }

    private NodeRequestMessage encode(Map<String,Object> commandMap){
        for (String id : commandMap.keySet ()){
            byte[] data = null;
            Integer oper = CommandOperations.get (id);
            Object obj = commandMap.get (id);
            if(obj != null){
                AdjustableParam param = (AdjustableParam)obj;
                data = new byte[]{param.getValue ()};
            }
            int length = data != null?data.length + 4 : 4;
            return new NodeRequestMessage (getzhnyType() + 128,length,oper,Integer.parseInt (getConfig ().getAddress ()),data);
        }
        return null;
    }

    @Override
    public void onDecoder(GatewayResponseMessage message) {
        logger.info (message.toString ());
        int type = message.getDeviceType ();
        if(type == 0x16){
            onMessage(message);
        }
        message.getDeviceData ().release ();
    }

    private void onMessage(GatewayResponseMessage message){
        MessageEntry resultMsg = MessageUtils.createMessageEntry (this.getId ());
        AdjustValveStoreEntry storeEntry = null;
        int operation = message.getDeviceOper ();
        if(operation >= 0x01 && operation <= 0x08){
            if(message.getDataLength () != 6){
                resultMsg.setType (MessageType.ERROR);
                resultMsg.setData ("水利机械阀加入任务失败");
                logger.error ("[deviceNo:{},controllerNo:{}] 水利机械阀加入任务[{}]失败"
                        , getConfig ().getAddress (), getConfig ().getChannelNo (), operation);
                nofity (resultMsg);
                return;
            } else if(operation == 1){
                storeEntry = new AdjustValveStoreEntry ();
                storeEntry.setA (Integer.valueOf (message.getDeviceData ().readUnsignedByte ()));
                resultMsg.setData (storeEntry);
            } else if(operation == 3){
                storeEntry = new AdjustValveStoreEntry ();
                storeEntry.setB (Integer.valueOf (message.getDeviceData ().readUnsignedByte ()));
                resultMsg.setData (storeEntry);
            } else if(operation == 5){
                storeEntry = new AdjustValveStoreEntry ();
                storeEntry.setC (Integer.valueOf (message.getDeviceData ().readUnsignedByte ()));
                resultMsg.setData (storeEntry);
            } else if(operation == 7){
                storeEntry = new AdjustValveStoreEntry ();
                storeEntry.setD (Integer.valueOf (message.getDeviceData ().readUnsignedByte ()));
                resultMsg.setData (storeEntry);
            }
        } else if(operation == 9) {
            storeEntry = new AdjustValveStoreEntry ();
            storeEntry.setA (Integer.valueOf (message.getDeviceData ().readUnsignedByte ()));
            message.getDeviceData ().readByte ();    //跳过阀门1的压力开度值
            storeEntry.setB (Integer.valueOf (message.getDeviceData ().readUnsignedByte ()));
            message.getDeviceData ().readByte ();    //跳过阀门2的压力开度值
            storeEntry.setC (Integer.valueOf (message.getDeviceData ().readUnsignedByte ()));
            message.getDeviceData ().readByte ();    //跳过阀门3的压力开度值
            storeEntry.setD (Integer.valueOf (message.getDeviceData ().readUnsignedByte ()));
            message.getDeviceData ().readByte ();    //跳过阀门4的压力开度值
            resultMsg.setData (storeEntry);
        }else if(operation == 0x0B){
            storeEntry = new AdjustValveStoreEntry();
            storeEntry.setVoltage (createVol(message.getDeviceData ().readUnsignedShort ()));
            resultMsg.setData (storeEntry);
        }
        resultMsg.setType (MessageType.RESULT);
        save (storeEntry);
        saveReal (storeEntry);
        nofity (resultMsg);
    }

    private double createVol(int vol)
    {
        return vol / 1000.0;
    }

    protected void disposable() {

    }
}
